perm filename VDSK.OLD[CMS,LCS]5 blob sn#412591 filedate 1979-02-02 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00028 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	Floppy disk file system.
C00006 00003	OCTL:	0	Lsbyte of octal to decimal.
C00008 00004	ID0:	113	Write two sectors.
C00009 00005	Add restore to retry?
C00011 00006	IDLSET:	LDAI	0
C00013 00007	DCODE:	LDXI	NCMDS	# of commands.
C00015 00008	Write command to FDSKC. No wait or * NTRYS.
C00017 00009	IRQ maskable interrupt routine.
C00019 00010	Non-maskable DRQ interrupt.
C00020 00011	Directory look up.
C00022 00012	Read 1st sec of a directory. Returns with 0 or Ebits.
C00024 00013	Open read file.
C00026 00014	Read a block of the file.
C00028 00015	Create file routine
C00030 00016	Write file.
C00032 00017	SWBUF:	JSR	SWDBUF	Swap disk buffers.
C00033 00018	CLOZE:	JSR	GEOT	Wait for EOT.
C00035 00019	Update directory header.
C00037 00020	PSF:	JSR	GEOT
C00039 00021	Delete file.
C00041 00022	DIR:	JSR	GEOT	Wait for EOT.
C00044 00023	Compress holes.
C00046 00024	FBUF ← File directory.
C00048 00025	FIXDIR:	CLV	V ← 0.
C00051 00026	FORM:	JSR	GEOT
C00053 00027	Decimal output routine.
C00055 00028	GDIG:	STAZ	DIGIT
C00057 ENDMK
C⊗;
;Floppy disk file system.
.INSERT ASMBL.FAI[CMS,LCS]
   ZERO ← 0
   LOC ZERO ;Fail offset

CBLK:	0	;Ram command block.
CCNT:	0	;C parameter count.
CLEN:	0	;C # of sectors.
CSEC:	0	;C sector
CTRK:	0	;C track
	0
FOTRK:	0	;Format track number.
	0
FCMD:	0	;Disk command pointer.
FCMDH:	0
CMDJMP:	0	;Indirect command jump.
CJMPH:	0	;Msbyte.
ERFLG:	0	;Error flag/code.
SVERR:	0	;Saved error.
CEFLG:	0	;Communication error flag.
RFOPEN:	0	;Read file open flag.
WFOPEN:	0	;Write file open flag
DIRC:	0	;Data direction
FLEN:	0	;File length. In sectors.
FITRK:	0	;Compress file track.
FISEC:	0	;Compress file sector.
SREM:	0	;Sectors remaining.
NTRYS:	0	;Number of retrys before error.
BUSY:	0	;Busy flag
MO:	0	;Motor on flag. MFLG = TL or TH?
TL:	0	;Motor time out low.
TH:	0	;Time out high.
DIRCNT:	0	;Directory sector count.
HLEN:	0	;Hole sector count.
HTRK:	0	;Hole track number.
HSEC:	0	;Hole sector number.
SVHY:	0	;Hole directory index. HDI.
SVHSEC:	0	;Hole directory sector. HDS.
SVSEC:	0	;Other directory sector. FDS.
SVOSEC:	0	;Old directory sector.

FBLK:	0	;File block
FNAME:	BLOCK 11	;9 Chr file name.
NSEC:	0	;Number of sectors in file.
FTRK:	0	;Disk track number
FSEC:	0	;Disk sector number
	BLOCK 3
DBLK:	0	;Directory block
DSEC:	0	;Number of sectors in directory.
FFDIR:	0	;First free directory block. FDI?
FFTRK:	0	;First free data track
FFSEC:	0	;First free data sector
FBLKS:	0	;Number of free sectors. In sectors.
FBH:	0	;Msbyte
	0
CKSUM:	0	;Check sum.
SPOINT:	0	;SI/O pointer.
SPOH:	0	;Msbyte
DPOINT:	0	;Disk buffer bointer.
DPOH:	0	;Msbyte
OCTL:	0	;Lsbyte of octal to decimal.
OCTH:	0	;Msbyte.
DIGIT:	0	;Tens or hundreds.

   LOC ZERO+1000
FBUF:	0	;Disk data buffer.
   LOC FBUF+400
FBUF1:	0	;Other buffer.

;PROM Start address.
   LOC ZERO+174000
FCTBL:
   DINIT ← 0
	65	;Specify
	4	;Parameter count.
	252	;H unload I cnt./ H load time.
	=25	;Head settling time in ms*2.
	=20	;Step rate in ms*2.
	15	;Init
   SBT ← 6
	65	;Specify
	4
	0	;Current track.
	377
	377	;No bad tracks.
	20	;Surface zero bad tracks command.
   DMA ← 14
	172	;Write special register.
	2
	0	;DMA and double actuator.
	27	;Mode register.
   RESTOR ← 20
	151	;Seek track zero command.
	1	;With head load.
	0	;Track zero
   MON ← 23
	172	;Write special register.
	2	;Clear out pins.
	40	;Motor on bit.
	43	;Drive control output register.
   MOFF ← 27
	172	;Write special register.
	2
	0	;Motor off.
	43	;Drive control output register.
   RDSTAT ← 33
	154	;Read drive status command.
	0
RH0:	123	;Read two sectors command.
	3
	2	;# of sectors.
	1	;Header sector number
	0	;Header track number
WH0:	113	;Write two sectors command.
	3
	2	;# of sectors.
	1	;Header sector number.
	0	;Header track number.
ID0:	113	;Write two sectors.
	3
	=16	;# of sectors.
	1	;First sector.
	0	;Track zero.
FORMT:	143	;Format track command.
	5
	=16	;Gap 1 -6.
	0	;Gap 5. No index mark.
	=16	;Sectors per track.
	=27	;Gap 3 -6.
	0	;Format track number.

   RETRY ← =10	;Number of retrys until error.
   DMARK ← 74	;Directory mark
   FMARK ← 72	;File mark
   HMARK ← 67	;Hole mark.
;Add restore to retry?
;Add write protect and not ready error codes.

;Power on reset.
RST:	LDXI	377	;Setup stack.
	TXS
	CLD	;Clear decimal mode.

;Reset I/O
   SIOC  ← 20000	;SI/O command register.
   SIOD  ← 20001	;SI/O data register.
   FDSKC ← 10000	;Disk command/status register
   FDSKP ← 10001	;Disk parameter/result register
   FDSKR ← 10002	;Disk reset register.
   FDRQ  ← 14000	;Disk DMA data request

;Init floppy disk controller.
	LDAI	1	;Reset disk again.
	STA	FDSKR
	NOP
	NOP
	NOP
	LSRA	;Clear A
	STA	FDSKR
	STAZ	MO	;Init motor flag.
		;A = DINIT
	JSR	PCMD	;Prom command.
	LDAI	DMA	;Setup DMA mode.
	JSR	PCMD

	LDXI	11	;10 = 1.3s.
	STXZ	TH
RLOOP:	DEX	;Power on delay.
	BNE	RLOOP
	DECZ	TL
	BNE	RLOOP
	DECZ	TH
	BNE	RLOOP

	LDAI	RESTOR	;Restore track zero.
	JSR	PCMD
	LDAI	SBT	;Setup bad tracks
	JSR	PCMD
;Reset SI/O
	LDAI	3	;Reset bits
	STA	SIOC
	LDAI	25	;ACIA control word.
	STA	SIOC

;Init RAM
	LDAZ	DSEC
	STAZ	DIRCNT	;Point to end of directory.
IDLSET:	LDAI	0
	STAZ	RFOPEN	;Reset read file open flag.
	STAZ	WFOPEN	;Clear write file open flag.

	STAZ	CEFLG	;Clear comm. error flag.
	STAZ	ERFLG	;Clear error flag.
	STAZ	SVERR	;Clear other error flag.

	STAZ	DIRC	;Set disk to read.
	STAZ	BUSY	;Set to not busy.
	CLI	;Enable interrupts.

   TWOS ← 4	;3 = 1.77s, 4 = 2.3s.
IDLE:	BITZ	MO	;Check if motor on.
	BPL	GSOH
	LDA	SIOC	;Read SI/O status.
	LSRA	;Get rcvr. full bit.
	BCS	GSOH

	DEX	;Time out countdown.
	BNE	IDLE
	DECZ	TL
	BNE	IDLE
	DECZ	TH
	BNE	IDLE

	INX
	INCZ	TL
	INCZ	TH
	BITZ	BUSY	;Check if disk is busy.
	BMI	IDLE
	LDAI	MOFF	;Turn motor off.
	JSR	PCMD
	STYZ	MO	;Motor on flag.

GSOH:	JSR	GCHR	;Wait for SOH.
	CMPI	1	;<SOH>.
	BNE	ILLCMD	;Error.
	JSR	GCHR	;Wait for command.
DCODE:	LDXI	NCMDS	;# of commands.
DL:	CMPX	CMDTBL	;Check if valid command.
	BEQ	JCMD
	DEX
	BPL	DL
;Illegal command.
ILLCMD:	LDXI	4	;Command error code.
OCLR:	JSR	OCHR	;Output status.
	JMP	IDLSET	;Reset flags.

JCMD:	LDAX	JLTBL	;Get lsbyte of jump address.
	STAZ	CMDJMP
	LDAX	JHTBL	;Get msbyte.
	STAZ	CJMPH

	JMPIN	CMDJMP	;Excute command.

   NCMDS ← =9	;# of commands -1.
CMDTBL:	"P"	;Perform special function.
	"K"	;Delete file.
	"B"	;Free blocks
	"N"	;Next directory block.
	"D"	;Open directory.
	"C"	;Close write file.
	"E"	;Enter write file.
	"O"	;Open read file.
	"W"	;Write data
	"R"	;Read data

JLTBL:	PSF∧377	;Lsbyte of command address.
	KIL∧377
	BLKS∧377
	NXTDIR∧377
	DIR∧377
	CLOZE∧377
	ENTR∧377
	OPIN∧377
	WRITE∧377
	READ∧377

JHTBL:	PSF⊗-10	;Msbyte of command address.
	KIL⊗-10
	BLKS⊗-10
	NXTDIR⊗-10
	DIR⊗-10
	CLOZE⊗-10
	ENTR⊗-10
	OPIN⊗-10
	WRITE⊗-10
	READ⊗-10
;Write command to FDSKC. No wait or * NTRYS.
PCMD:	STAZ	FCMD	;Prom command with no retrys.
	LDAI	370	;Msbyte of command table addr.
	STAZ	FCMDH
	LDAI	0
	STAZ	NTRYS
	BEQ	SETPO	;Jump.

RCMD:	LDAI	0	;Ram command with no retrys.
SETRY:	STAZ	NTRYS
TRY:	LDAI	0
	STAZ	FCMD
	STAZ	FCMDH

	LDAI	377	;Set busy.
	STAZ	BUSY
	LDAI	0
SETPO:	STAZ	DPOINT	;Reset disk DMA pointer.

BSYW:	LDA	FDSKC	;Wait until not busy.
	BMI	BSYW

	LDYI	0
	LDAIY	FCMD	;Get command code.
	STA	FDSKC	;Write in disk control reg.

	INCZ	FCMD	;Point to parameter count.
	LDAIY	FCMD	;Get count.
	BEQ	NOPAR	;If no parameters
	TAY

PARW:	LDA	FDSKC	;Read status
	ANDI	40	;P reg full bit.
	BNE	PARW	;Wait if still full.

	LDAIY	FCMD	;Parameter
	STA	FDSKP
	DEY
	BNE	PARW	;More left?

NOPAR:	RTS	;Y = 0

WBUFR:	LDAI	113	;Write two sectors command.
	STAZ	CBLK
WUF:	LDAI	377
	STAZ	DIRC	;Set to write.

;Disk command with retrys on read error.
RCMDR:	LDAI	RETRY	;RAM disk command.
	BNE	SETRY

RCMDW:	JSR	RCMDR	;Read command wait.
BW:	BITZ	BUSY
	BMI	BW	;Wait until done
	LDAZ	ERFLG	;Get error bits.
	RTS	;Return with error bits.
;IRQ maskable interrupt routine.
IRQV:	PHA	;Save Registers.
	TYA
	PHA
   ;Wait for result bit?
	LDA	FDSKP	;Read disk result register.
	ANDI	36	;Flush ddbit
	STAZ	ERFLG

	LDYI	200
CKIRQ:	INY	;IRQ reset delay.
	BNE	CKIRQ

	TAY	;Test error flags.
	BNE	DSKERR	;Disk error.
	LDAZ	CBLK	;Get last disk command.
	CMPI	113	;Check if write command.
	BNE	NOTBSY

	LDAI	137	;Disk verify command.
	STAZ	CBLK
	BNE	ITRY	;Verify write.

DSKERR:	ANDI	20	;Bad bit
	BEQ	CKTRY
;Dsk error: RDY,WRT fault, etc.
;Fix for WPRT etc.
	STAZ	SVERR	;Save bad error.
;Read drive status if not ready for clear.
   ;Check if not ready?
	LDAI	RDSTAT	;Read drive status.
	JSR	PCMD	;No interrupt.
	JSR	GRSLT	;Wait for result.
;20 Not ready.
;21 Write protect.
;22 Restore error.
;23 File not found.
;30 Sector not found.
	JMP	NOTBSY

CKTRY:	LDAZ	NTRYS
	BEQ	SETERR
	
	DECZ	NTRYS
ITRY:	JSR	TRY	;Retry command.
	BEQ	RTRN	;Jump. Wait until done.

SETERR:	LDAI	377	;Retry error.
	STAZ	SVERR

NOTBSY:	LDAI	0
	STAZ	BUSY	;Set done
	STAZ	DIRC	;Reset to read.
	BEQ	RTRN	;Jump.
;Non-maskable DRQ interrupt.
NMIV:	PHA	;Save registers
	TYA
	PHA
	LDYI	0	;No index.

	BITZ	DIRC	;Get direction.
	BMI	WDRQ	;Disk write.

	LDA	FDRQ	;Read byte from disk.
	STAIY	DPOINT	;Save it in FBUF

INCPO:	INCZ	DPOINT

RTRN:	PLA	;Restore Registers.
	TAY
	PLA
	RTI	;Return

WDRQ:	LDAIY	DPOINT	;Get byte from FBUF.
	STA	FDRQ	;Write into disk data register.
	JMP	INCPO
;Directory look up.
;Returns with file found, fnf, or read error.(0,200,XX)
LOKUP:	LDXI	0
GNAME:	JSR	GCHR	;Get name.
	CMPI	4	;<EOT>.
	BEQ	CKNAME
	STAZX	FNAME
	INX
	CPXI	=10	;9 Chr file name + EOT.
	BCC	GNAME

ILCJMP:	PLA	;One level pop to ILLCMD.
	PLA
	JMP	ILLCMD

CKNAME:	TXA	;Test X.
	BEQ	ILCJMP	;No file name.
	LDAI	" "	;<Space>.
PAD:	STAZX	FNAME	;Pad file name with spaces.
	INX
	CPXI	=9
	BCC	PAD

	JSR	RHDR	;Read directory header sector.
	BNE	LUERR
	LDAI	FMARK
	STAZ	FBLK

GETS:	JSR	RNDS	;Read next 2 directory sectors.
	BNE	LUERR
		;Y = 0
CKDIR:	LDXI	0
CKNAM:	LDAY	FBUF
	CMPZX	FBLK	;Look for file name.
	BNE	NXTF	;No match
	INY
	INX
	CPXI	=10	;9 chrs. + FMARK.
	BCC	CKNAM
;Names match
FMOV:	LDAY	FBUF	;Save file record.
	STAZX	FBLK
	INY
	INX
	CPXI	20
	BCC	FMOV

	LDAI	0	;Return with file found.
LUERR:	RTS	;Return with error bits.

NXTF:	TYA	;Point to next file record.
	ORAI	17
	TAY
	INY
	BNE	CKDIR

	DECZ	SREM	;Check if more sectors.
	DECZ	SREM
	BNE	GETS
	LDAI	200	;Return file not found code.
	RTS
;Read 1st sec of a directory. Returns with 0 or Ebits.
RHDR:	JSR	MOTON	;Turn on motor and delay.
	LDXI	4
CSET:	LDAX	RH0	;Setup command list.
	STAZX	CBLK
	DEX
	BPL	CSET

	JSR	SETDPO	;Point disk to FBUF.
	JSR	RSEC	;Read it * 16.
	BNE	HERR
	LDA	FBUF
	CMPI	DMARK	;Check for directory.
	BNE	HERR

	LDXI	7
GHL:	LDAX	FBUF
	STAZX	DBLK
	DEX
	BPL	GHL
	LDAZ	DSEC
	STAZ	SREM	;Number of sectors in dir.
	STAZ	DIRCNT	;Reset directory count.
	LDAI	0	;No error return
HERR:	RTS	;Return with error bits.

;Read a block routine.
REED:	LDAI	123	;Read two sectors command.
	STAZ	CBLK
	BNE	RSEC
;Read next dir. sector. Returns with error bits.
RNDS:	INCZ	CSEC	;Read next dir sec.
	INCZ	CSEC
RSEC:	LDAI	0	;Reset file open flags.
	STAZ	RFOPEN
	STAZ	WFOPEN

	JSR	RCMDW	;Disk command wait * RETRYS
	BEQ	GOTIT	;Good read
	INY	;Y ← 1. Directory 1.
	STYZ	CTRK
	JSR	RCMDW	;Y ← 0
	STYZ	CTRK	;Fix CTRK for next read.
GOTIT:	RTS	;Return with error bits.

SETDPO:	LDAI	FBUF⊗-10	;Point disk to FBUF.
	STAZ	DPOH
	LDAI	0
	STAZ	DPOINT
	RTS

INCSEC:	INX	;Increment sector and track address.
	INX
	CPXI	=16
	BCC	NXTBLK
	ADCI	0	;TRK ← TRK + 1.
	LDXI	1	;First sector.
NXTBLK:	RTS
;Open read file.
OPIN:	BITZ	WFOPEN	;Check if write file open.
	BPL	LOOK
	JMP	FAO	;File already open error.

LOOK:	JSR	LOKUP	;Lookup file FNAM
	BEQ	SETOPN
	CMPI	200	;File not found code.
	BEQ	NACKIT
	JMP	DIRERR	;Directory read error
NACKIT:	JMP	FNF	;File not found.

SETOPN:	LDAZ	FTRK	;Get track and sector
	STAZ	CTRK
	LDAZ	FSEC
	STAZ	CSEC
	LDAZ	NSEC	;Get file length.
	STAZ	SREM
;Fill FBUF
	JSR	RCMDR	;* NTRYS and no wait.

	JSR	SETSPO	;Point SPOINT to FBUF.
	LDAI	377
	STAZ	RFOPEN

ACK:	LDXI	20	;<ack>
OACK:	JSR	OCHR	;Output byte.
	JMP	IDLE	;No flag clear.

SETSPO:	LDAI	FBUF⊗-10	;Reset SI/O pointer.
	STAZ	SPOH
	LDAI	0
	STAZ	SPOINT
	RTS
;Read a block of the file.
READ:	JSR	GEOT	;Wait for EOT.
	BITZ	RFOPEN	;Check if file open.
	BMI	CKS
	JMP	FNF	;File not found
CKS:	LDAZ	SREM	;Check for end of file.
	BNE	READO	;For FLEN = 0.
EOF:	LDXI	6	;End of file error code.
	JMP	OCLR	;Output X and clear flags.

READO:	JSR	BW	;Wait until not busy.
	BEQ	NXTBUF
DRERR:	LDXI	14	;Disk read error.
	JMP	OCLR	;Clear all flags.

NXTBUF:	STAZ	CKSUM
	DECZ	SREM	;Check if end of file.
	DECZ	SREM
	BEQ	ACKIT
   ;Start read of next buffer.
	LDXZ	CSEC
	LDAZ	CTRK
	JSR	INCSEC	;Get next sector.
	STXZ	CSEC
	STAZ	CTRK

RNS:	JSR	SWDBUF	;Swap disk buffers.
	JSR	MOTON	;Turn on motor.
	JSR	RCMDR	;No wait. Y=0. Set CBLK?
ACKIT:	JSR	ACKSTX	;Output <ack> and <stx>.
		;Y = 0
RDIT:	LDAIY	SPOINT	;Output a buffer full.
	TAX
	CLC
	ADCZ	CKSUM
	STAZ	CKSUM
	JSR	OCHR
	INY
	BNE	RDIT

	JSR	SWSBUF	;Swap SI/O buffers.
OUTCK:	LDAZ	CKSUM	;Output check sum.
	EORI	377
	TAX
	INX
	JMP	OACK	;Output it and no flag clear.

SWSBUF:	LDAZ	SPOH
	EORI	1	;Swap SI/O buffers.
	STAZ	SPOH
	RTS
;Create file routine
ENTR:	BITZ	WFOPEN	;Check if file already open
	BPL	LOKIT
FAO:	LDXI	10	;File already open error.
	BNE	OAJMP	;Output it. No flag clear.
LOKIT:	JSR	LOKUP	;Check if file already exists.
	BEQ	FEXIST	;Check if file exists
	CMPI	200	;Not in dir. code
	BEQ	FULCK
DIRERR:	LDXI	13	;Directory read error code.
CLRJMP:	JMP	OCLR	;Clear flags.

FEXIST:	LDXI	2	;File exists error code.
	BNE	CLRJMP	;Clear flags.

DSKFUL:	LDAI	=35	;Disk full.
	STAZ	FFTRK	;Set full flag.
DFUL:	LDXI	5	;Disk full code.
OAJMP:	JMP	OACK	;No flag clear?

FULCK:	LDAZ	FFTRK	;Get first free track.
	CMPI	=35	;Check if disk full.
	BCS	DFUL

	STAZ	CTRK	;Point to new file.
	STAZ	FTRK	;Setup file block.
	STAZ	CLEN	;Track number for seek.
	LDAI	151	;Seek track command.
	STAZ	CBLK
	LDAI	1
	STAZ	CCNT

	JSR	RCMD	;Seek track. Y = 0
	STYZ	FLEN	;Reset file length.

	DEY	;Set write file open flag.
	STYZ	WFOPEN

	LDXI	3	;Setup command parameter count.
	STXZ	CCNT
	STXZ	DPOH	;Point disk to other buffer.
	DEX	;Setup number of sectors.
	STXZ	CLEN
	LDXZ	FFSEC
	STXZ	FSEC	;Setup file block.
	DEX	;-2 For inc. before write.
	DEX
	STXZ	CSEC

	JSR	SETSPO	;Point SI/O to FBUF.
	JMP	ACK	;Return with no errors
;Write file.
WRITE:	JSR	GEOT	;Wait for EOT.
	BITZ	WFOPEN	;Check if file open.
	BMI	WIT
	JMP	FNF	;File not found
WIT:	LDAZ	FFTRK
	CMPI	=35	;Check if disk is full.
	BCS	DSKFUL

	JSR	PACK	;Output <ACK>.
	JSR	GCHR	;Wait for STX.
	CMPI	2	;<STX>.
	BNE	COMERR	;No STX.

	LDYI	0
	STYZ	CKSUM	;Init check sum.

WLOOP:	JSR	GCHR	;Fill FBUF.
	STAIY	SPOINT
	CLC
	ADCZ	CKSUM	;Update check sum.
	STAZ	CKSUM
	INY
	BNE	WLOOP

	JSR	GCHR	;Get check sum.
	CLC
	ADCZ	CKSUM	;Check for check sum error.
	BNE	COMERR
	LDAZ	CEFLG	;Check for communication error.
	BEQ	WBUF
COMERR:	LDXI	11	;Communication error.
	JMP	OCLR	;Reset flags.

WBUF:	JSR	BW	;Wait until last buffer done.
	BEQ	NFBLK
	JMP	DRERR	;Write error. Verify error?
NFBLK:	LDXZ	CSEC	;Fix sector number.
	LDAZ	CTRK
	JSR	INCSEC
	STXZ	CSEC
	STAZ	CTRK
	CMPI	=35	;Check if disk is full.
	BCC	SWBUF
	JMP	DSKFUL
SWBUF:	JSR	SWDBUF	;Swap disk buffers.
	JSR	MOTON	;Turn on motor.
	JSR	WBUFR	;Write buffer.
	
	JSR	SWSBUF	;Swap SI/O buffers.
	INCZ	FLEN	;Update file length.
	INCZ	FLEN
	JMP	ACK	;No error return.

WBUFW:	JSR	WBUFR	;Write it.
	JMP	BW	;Return with E bits when done.

SWDBUF:	LDAZ	DPOH
	EORI	1	;Swap disk buffers.
	STAZ	DPOH
	RTS
CLOZE:	JSR	GEOT	;Wait for EOT.
	BITZ	WFOPEN	;Check if file open
	BMI	UPDIR
	JMP	ACKCLR	;No file open, <ack> anyway.

;Update directory
UPDIR:	JSR	BW	;Wait until not busy.
	BEQ	BUMP
	JMP	DRERR	;Last buffer write error?

BUMP:	LDAZ	FLEN	;Save file length.
	STAZ	NSEC
	LDAZ	CTRK	;Save new FFTRK.
	LDXZ	CSEC	;Point to next free data block.
	JSR	INCSEC
	STAZ	HTRK
	STXZ	HSEC	;Save new FFSEC.

;Read last directory sector.
	JSR	MOTON	;Turn on motor.

	LDXZ	DSEC	;Last directory sector -1.
	INX	;Bump.
	STXZ	CSEC
	STXZ	SVOSEC	;Save last dir. sec. number.
	JSR	SETDPO	;Point to FBUF. A ← 0
	STAZ	CTRK	;Track zero.
	JSR	REED	;Read next dir. sec.
	BEQ	CLOZIT
CLZERR:	JMP	DIRERR	;Directory read error.

CLOZIT:	LDYZ	FFDIR

	TAX	;X ← 0
NAMEIT:	LDAZX	FBLK	;BLT FBLK into directory
	STAY	FBUF
	INY
	INX
	CPXI	20	;FBLK Length
	BCC	NAMEIT
;Update directory header.
WRTH0:	TYA	;Get next free directory block.
	STAZ	FFDIR
	BNE	UPFF
	INCZ	DSEC	;Next sector
	INCZ	DSEC
	LDAZ	DSEC	;Check if directory full.
	CMPI	=15
	BCC	UPFF
	LDAI	=14	;Last directory sector.
	STAZ	DSEC
	LDAI	=35	;Set disk full.
	STAZ	HTRK
UPFF:	LDAZ	HSEC	;Point to next free block.
	STAZ	FFSEC
	LDAZ	HTRK
	STAZ	FFTRK
	SEC
	LDAZ	FBLKS
	SBCZ	FLEN	;Update free blocks.
	STAZ	FBLKS
	BCS	WDIR
	DECZ	FBH
WDIR:	LDXI	7	;Header length.
HLOOP:	LDAZX	DBLK	;BLT Header into directory.
	STAX	FBUF1	;Other buffer.
	DEX
	BPL	HLOOP

	LDAI	1	;First sector.
	STAZ	SVSEC
	JSR	WBUFS	;Write 4 bufs on 2 tracks.
	BNE	CLZERR	;Check for close error.
	STAZ	WFOPEN	;Close write open flag.
ACKCLR:	LDXI	20	;<Ack>.
	JMP	OCLR	;Output <Ack> and clear flags.

   ;Add error checks after WBUFWs?
WBUFS:	JSR	WBUFW	;Write dir. 0.

	LDAZ	SVSEC	;First sector.
	STAZ	CSEC
	JSR	SWDBUF	;Swap disk buffers.

	JSR	WBUFW	;Write dir. header 0. Y←0
	INY	;Y ← 1. Directory 1.
	STYZ	CTRK
	JSR	WBUFW	;Write dir. header 1.
   ;Write last track directory.
	LDAZ	SVOSEC	;Get last dir.sec. number.
	STAZ	CSEC
	JSR	SWDBUF	;Swap buffers.
	JSR	WBUFW

	LDAZ	SVERR	;?
	RTS	;Return with error bits.
PSF:	JSR	GEOT
	JSR	PACK	;<Ack>
	JSR	GCHR	;Wait for SOH.
	CMPI	1	;SOH
	BNE	PSFERR
	JSR	GCHR	;Wait for special function cmd.
	CMPI	"Q"	;Compress holes.
	BNE	CKF
	JSR	GEOT	;Wait for EOT.
	JMP	CMPRES

CKF:	CMPI	"F"	;Format disk.
	BNE	CKI
	JMP	FORM
CKI:	CMPI	"I"	;Initialize directory.
	BEQ	IDIR
PSFERR:	JMP	ILLCMD	;Command error.
;Initialize directory.
IDIR:	JSR	GEOT	;Wait for EOT.
	JSR	MOTON	;Turn on motor.
FORMIN:	LDXI	10	;Entry from format command.
	LDAI	0
ZE:	STAX	FBUF	;Zero directory
	INX
	BNE	ZE
	LDXI	7
DIIL:	LDAX	DIT	;Init dir.
	STAX	FBUF
	DEX
	BPL	DIIL

	LDXI	4
SETC:	LDAX	ID0	;Setup CBLK.
	STAZX	CBLK
	DEX
	BPL	SETC

	JSR	SETDPO	;Point disk to FBUF.
	JSR	WS2TRK	;Write sector on two tracks.
	BNE	IDERR
	JMP	ACKCLR	;<Ack> and clear flags.

IDERR:	LDXI	7	;Init dir. error.
	JMP	OCLR	;Reset flags.

WS2TRK:	JSR	WBUFW	;Write first header and dir.
	LDAI	1	;Directory 1.
	STAZ	CTRK
	JSR	WBUFW	;Write last directory.
	LDAZ	SVERR	;Return with all errors.
	RTS

DIT:	DMARK
	2	;# of sectors
	0	;FFDB
	2	;FFT
	1	;FFS
	=528∧377	;FBL
	=528⊗-10	;FBH
	0
;Delete file.
KIL:	JSR	LOKUP
	BEQ	KILIT
   ;Check for directory read error?
FNF:	LDXI	3	;File not found.
	JMP	OCLR
KILIT:	DEY	;Fix directory pointer.
	LDAI	HMARK
	STAY	761	;FBUF - 17
	LDXZ	CSEC
	STXZ	SVOSEC	;Save directory sector #.
	INY	;Next directory block.
	CPYZ	FFDIR	;Check if last dir. block.
	BNE	DEL
	DEX
	TYA	;A ← Old FFDIR.
	BNE	CKSEC
	INX
	INX
CKSEC:	CPXZ	DSEC	;Check if last block in dir.
	BNE	DEL
	SEC
	SBCI	20	;Point to FFDIR -1 block.
	STAZ	FFDIR
	TYA	;Test Y.
	BNE	DEL
	DECZ	DSEC	;Directory sector -2.
	DECZ	DSEC

DEL:	JMP	WDIR	;Write header and directory.

;Output free blocks.
BLKS:	JSR	GEOT	;Wait for EOT.
	JSR	RHDR	;Read directory header.
	BNE	JDER	;Directory read error.
	JSR	ACKSTX	;Output <ack> and <stx>.
	LDAZ	FBH	;Get msbyte of free blocks.
	LDXZ	FBLKS	;Get lsbyte.
	JSR	ODEC	;Output 3 decimal digits.
OEOT:	LDXI	4	;<EOT>.
	JMP	OCLR	;Clear flags.

GRSLT:	LDA	FDSKC	;Read disk status.
	BMI	GRSLT	;Wait until not busy.
	LDA	FDSKP	;Get result.
	RTS
DIR:	JSR	GEOT	;Wait for EOT.
	JSR	RHDR	;Read header.
	BEQ	RQDIR
JDER:	JMP	DIRERR	;Error.
RQDIR:	LDAI	0	;Point to start
	STAZ	DIRCNT
JACK:	JMP	ACKCLR	;<Ack> and clear flags.

NXTDIR:	JSR	GEOT	;Wait for EOT.
	LDXZ	DIRCNT	;Check if at end.
	CPXZ	DSEC	;Check if done.
	BCC	NXD
	JMP	EOF
NXD:	INX
	INX
	STXZ	DIRCNT	;Update directory count.
	INX	;Bump past dir. header.
	STXZ	CSEC
	JSR	MOTON	;Turn on motor.
	JSR	RSEC	;Read next directory sector.
	BNE	JDER
	JSR	ACKSTX	;Output <ACK> and <stx>.
	LDAI	(15+12)*=16
	STAZ	CKSUM	;Init check sum.
		;Y = 0
DOL:	LDAY	FBUF	;Find file in FBUF.
	CMPI	FMARK
	BNE	OUTZ
	LDXI	11	;9 Chr file name.
	STXZ	HSEC

ONAME:	LDXY	1001	;FBUF + 1.
        JSR	OCHRCK	;Output it.
	INY
	DECZ	HSEC
	BNE	ONAME
	LDXI	" "	;Output two spaces.
	JSR	OCHRCK	;Output and update check sum.
	JSR	OCHRCK	;Output and update check sum.
	LDAI	0	;Msbyte of file length.
	LDXY	1001	;Get lsbyte from FBUF.
	JSR	ODEC	;Output 3 ascii decimal digits.

CLOUT:	LDXI	15	;<CR>.
	JSR	OCHR
	LDXI	12	;<LF>.
	JSR	OCHR
	TYA
	ORAI	17	;Next file block.
	TAY
	INY
	BNE	DOL
	JMP	OUTCK	;Output check sum.

OUTZ:	LDAI	15	;9 chr. file name + 5 - 1.
	STAZ	HSEC
	LDXI	0	;Null file block. (Hole)
ZOUT:	JSR	OCHR	;Output nulls.
	DECZ	HSEC
	BPL	ZOUT
	BMI	CLOUT	;Jump.
;Compress holes.
CMPRES:	JSR	RHDR	;Read directory header.
	BNE	DJ
SQEZ:	JSR	RNDS	;Read directory.
	BNE	DJ
		;Y = 0
CKHOL:	LDAY	FBUF
	CMPI	HMARK	;Look for a hole?
	BEQ	HOLE	;Not for no FMARK?
	TYA
	CLC
	ADCI	20	;Next directory record.
	TAY
	BNE	CKHOL

	DECZ	SREM	;SREM ← SREM - 2.
	DECZ	SREM
	BNE	SQEZ
PACKED:	JMP	ACKCLR	;Done.
DJ:	JMP	DIRERR	;Directory read error.

;Hole found.
HOLE:	LDAY	1013	;FBUF + TRK#
	STAZ	HTRK	;Save hole track.
	LDAY	1014	;FBUF + SEC#
	STAZ	HSEC	;Save hole sector.
	STYZ	SVHY	;Save hole dir. index.
	LDAZ	CSEC
	STAZ	SVHSEC	;Save hole dir. sector.

FINDF:	CLC	;Update free blocks?
	LDAZ	FBLKS
	ADCY	1012	;FBUF + FLEN.
	STAZ	FBLKS
	BCC	FNXTF
	INCZ	FBH

FNXTF:	TYA	;Find next file.
	CLC
	ADCI	20	;Next dir. record.
	TAY
	BNE	CKFIL
	DECZ	SREM	;SREM ← SREM - 2.
	DECZ	SREM
	BNE	GSEC
	JMP	DONE	;?

GSEC:	LDAI	123	;Read two sectors command.
	STAZ	CBLK
	JSR	RNS	;Read next directory block.
	BNE	DJ	;Error.
	TAY	;Y ← 0.
CKFIL:	LDAY	FBUF	;Look for file mark.
	CMPI	FMARK
	BEQ	FFOUND
	CMPI	HMARK	;Check if a hole.
	BNE	FNXTF
	BEQ	FINDF	;Jump and add hole length.
;FBUF ← File directory.
   ;File found. Save file address.
FFOUND:	STYZ	FFDIR	;Save file directory index.
	LDAZ	CSEC	;Save file directory sector #.
	STAZ	SVSEC
	LDXI	0
	JSR	FMOV	;Save FBLK.
	LDXI	2
FILAD:	LDAZX	NSEC	;Save file addr. and length.
	STAZX	FLEN	;FLEN, FITRK, and FISEC.
	DEX
	BPL	FILAD
	JSR	SWDBUF	;Swap disk buffers.
;Fill hole.
	LDAZ	FITRK	;Point to file.
	LDXZ	FISEC
FILLIT:	STAZ	CTRK
	STXZ	CSEC
	LDAI	123	;Read two sectors command.
	STAZ	CBLK
	JSR	RCMDW	;Read a block.
	BNE	DJMP

	LDAZ	HTRK	;Point to hole.
	STAZ	CTRK
	LDXZ	HSEC
	STXZ	CSEC
	JSR	INCSEC	;Next hole sectors.
	STAZ	HTRK
	STXZ	HSEC
	JSR	WBUFW	;Fill hole.
	BNE	DJMP

	DECZ	FLEN	;FLEN ← FLEN - 2.
	DECZ	FLEN
	BEQ	CUPD	;Check if hole filled.
	LDXZ	FISEC
	LDAZ	FITRK
	JSR	INCSEC	;Next file sectors.
	STAZ	FITRK
	STXZ	FISEC
	BNE	FILLIT	;Jump.

CUPD:	LDAZ	SVHSEC	;Update directory.
	STAZ	CSEC	;Get hole dir. sector.
	STAZ	SVOSEC	;Save other sector number?
	LDAI	0	;Track zero.
	STAZ	CTRK
	JSR	REED	;Read hole dir. sector.
	BEQ	FIXDIR
DJMP:	JMP	DIRERR	;Directory read error.
FIXDIR:	CLV	;V ← 0.
	LDAZ	SVSEC	;Check if FDS = HDS.
	CMPZ	SVOSEC
	BEQ	ZEROX
	BIT	CKDUPE	;V ← 1.
ZEROX:	LDXI	0
	LDYZ	SVHY	;Get hole dir. index.
UPBLK:	LDAZX	FBLK	;FBUF1 ← FBLK - TRK&SEC
	STAY	FBUF1	;Other buffer.
	BVS	NXTXY	;If FDS = HDS...
	STAY	FBUF	;write into other buffer too.
NXTXY:	INY
	INX
	CPXI	13	;FMARK + FNAME & NSEC.
	BCC	UPBLK
;Find next file.
	LDAZ	SVHY	;Get HDI.
	TAY
	ADCZ	17	;Next file record - carry.
	STAZ	SVHY	;Next hole directory index.
	BNE	MARKIT
	INCZ	SVHSEC	;Next hole directory sector.
MARKIT:	LDAI	HMARK
	STAY	FBUF	;Old file ← hole.
	BVS	DIFFS	;Check if HDS = FDS.
	STAY	FBUF1	;Mark other buffer too.
	JSR	WS2TRK	;Write sector on two tracks.
	JMP	CKDUPE

DIFFS:	JSR	WBUFS	;Write 4 bufs on 2 tracks.
CKDUPE:	BNE	DJMP
	JSR	SETDPO	;Point disk to FBUF.
	STAZ	CTRK	;CTRK ← 0.
	LDAZ	SVSEC	;FDS
	STAZ	CSEC
	LDYZ	FFDIR	;Get file dir index.
	JMP	FNXTF	;Find next file.

DONE:	LDAZ	HTRK
	STAZ	FFTRK	;Update first free data track.
	LDAZ	HSEC
	STAZ	FFSEC	;Update first free data sector.
	LDYZ	SVHY	;Get first free dir. block.
	STAZ	FFDIR
	LDXZ	SVHSEC
	DEX
	STXZ	DSEC	;Update directory sector count.
	LDXI	7
BLTIT:	LDAZX	DBLK	;BLT Header into directory.
	STAX	FBUF
	DEX
	BPL	BLTIT

	JSR	WBUFW	;Write header 0.
	BNE	UPERR	;Write error.
	INY	;Y ← 1. Second track.
	STYZ	CTRK
	JSR	WBUFW	;Write header 1.
	BNE	UPERR	;Write error.
	JMP	ACKCLR	;Packed.
UPERR:	JMP	DIRERR	;?
FORM:	JSR	GEOT
	JSR	MOTON	;Turn on motor.

	JSR	SETDPO	;Point to FBUF.
	LDXI	6
CSLOP:	LDAX	FORMT	;Setup command list.
	STAZX	CBLK
	DEX
	BPL	CSLOP

TKOOP:	LDXI	1	;First sector.
	LDYI	0
SCOOP:	LDAZ	FOTRK	;Get track number.
	STAY	FBUF	;And setup I.D.s.
	INY
	LDAI	0
	STAY	FBUF	;Head number.
	INY
	TXA
	STAY	FBUF	;Sector number.
	INY
	LDAI	0
	STAY	FBUF	;Length.
	INY
	INX	;Next sector.
	CPXI	=17	;Sectors per track +1.
	BCC	SCOOP

	JSR	WUF	;Write buffer.
	JSR	BW	;Wait until not busy.
   ;Add verify 16 sectors? Check disk error?
	INCZ	FOTRK	;Next track.
	LDAZ	FOTRK
	CMPI	=35
	BCC	TKOOP

	LDAZ	SVERR	;Check for errors?
	BNE	UPERR	;Error.
	JMP	FORMIN	;Init directory.
;Wait for input.
GCHR:	LDA	SIOC	;Read SI/O status.
	LSRA	;Get rcvr. full bit.
	BCC	GCHR
	ANDI	30	;FE, OVR.
	BNE	CERR
	LDA	SIOD	;Input byte.
	RTS
CERR:	STAZ	CEFLG	;Save comm. error.
	LDAI	0	;Return with null.
	RTS

GEOT:	JSR	GCHR	;Wait for EOT.
	CMPI	4	;<EOT>
	BNE	TERR
	LDAZ	CEFLG	;Check for comm. error.
	BNE	TERR
	RTS
TERR:	PLA	;Fix stack.
	PLA
	JMP	ILLCMD
;Decimal output routine.
ODEC:	CLC
	RORA	;/2
	STAZ	OCTH
	TXA
	RORA
	STAZ	OCTL
	LDAI	=100
	JSR	GDIG	;Output hundreds.
	LDAI	=10
	JSR	GDIG	;Output tens.
	LDAZ	OCTL
	ORAI	60	;Convert to ascii.
	TAX

OCHRCK:	TXA
	CLC
	ADCZ	CKSUM	;Update check sum.
	STAZ	CKSUM
;Output byte in X.
OCHR:	LDA	SIOC	;Read SI/O status.
	ANDI	2	;Transmiter full bit.
	BEQ	OCHR
	STX	SIOD	;Output it.
	RTS
PACK:	LDXI	20	;Output <ack>.
	BNE	OCHR
ACKSTX:	JSR	PACK	;Output <ack> and <stx>.
PSTX:	LDXI	2	;Output <stx>.
	BNE	OCHR

   ONES ← 6	;6 = .98s, 7 = 1.15s.
MOTON:	BITZ	MO	;Check if already on.
	BMI	SPIN
	LDXI	377	;Turn on motor.
	STXZ	MO	;Set motor on flag.
	INX	;X ← 0.
	STXZ	TL	;Setup motor time out.
	LDAI	ONES
	STAZ	TH
	LDAI	MON	;Turn it on.
	JSR	PCMD

MW:	DEX	;Wait for motor on delay.
	BNE	MW
	DECZ	TL
	BNE	MW
	DECZ	TH
	BNE	MW

SPIN:	LDAI	0	;Setup motor time out.
	STAZ	TL
	LDAI	TWOS
	STAZ	TH
	RTS
GDIG:	STAZ	DIGIT
	LDXI	57	;"0" -1.
DIGLOP:	INX
	SEC
	LDAZ	OCTL
	SBCZ	DIGIT
	STAZ	OCTL
	BCS	DIGLOP
	DECZ	OCTH
	BPL	DIGLOP
	JSR	OCHRCK	;Output digit and update check sum.
	LDAZ	OCTL
	ADCZ	DIGIT
	STAZ	OCTL
	INCZ	OCTH
	RTS

;Reset and interrupt vectors.
   LOC ZERO + 177772
	NMIV∧377	;NMI Vector.
	NMIV⊗-10
	RST∧377	;Reset vector.
	RST⊗-10
	IRQV∧377	;IRQ Vector.
	IRQV⊗-10
END